#include "autostatus.h"


void network_connections_free(network_connection_t *connection)
{
    network_connection_t *tmp;
    while(connection != NULL)
    {
        tmp = connection;
        connection = tmp->next;
        g_free(tmp->id);
        g_free(tmp->type);
        g_free(tmp->uuid);
        g_free(tmp);
    }
}

network_connection_t *get_network_connection_by_path(DBusGConnection *dbus, char *setting_type, char *path)
{
    DBusGProxy *proxy;
	GError *error = NULL;
	GHashTable *hash = NULL;
	NMConnection *connection = NULL;
    NMSettingConnection *setting = NULL;
    network_connection_t *rt = NULL;
    const char *_tmp;

    proxy = dbus_g_proxy_new_for_name (dbus,
	                                   setting_type,
	                                   path,
	                                   NM_DBUS_IFACE_SETTINGS_CONNECTION);
	g_assert (proxy);

    /* Request the all the configuration of the Connection */
	if (!dbus_g_proxy_call (proxy, "GetSettings", &error,
	                        G_TYPE_INVALID,
	                        DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &hash,
	                        G_TYPE_INVALID)) {
		g_warning ("Failed to get active connection Connection property: %s",
		           error->message);
		g_error_free (error);
		goto out;
	}

    connection = nm_connection_new_from_hash (hash, &error);
	if (!connection) {
		g_warning ("Received invalid connection data: %s", error->message);
		g_error_free (error);
		goto out;
	}

    setting = NM_SETTING_CONNECTION(nm_connection_get_setting(connection, NM_TYPE_SETTING_CONNECTION));

    rt = (network_connection_t *)calloc(1, sizeof(network_connection_t));
    rt->next = NULL;

    _tmp = nm_setting_connection_get_id (setting);
    rt->id = strdup(_tmp);

    _tmp = nm_setting_connection_get_connection_type (setting);
    rt->type = strdup(_tmp);

    _tmp = nm_setting_connection_get_uuid (setting);
    rt->uuid = strdup(_tmp);

    out:
	if (connection)
		g_object_unref (connection);
	if (hash)
		g_hash_table_destroy (hash);

	g_object_unref (proxy);

    return rt;
}

network_connection_t *get_active_network_connection_by_path(DBusGConnection *dbus, char *obj_path)
{
    
    DEBUG("get actived connection by path start");
    DBusGProxy *props_proxy;
	GValue path_value = { 0 };
	GValue serv_value = { 0 };
	GError *error = NULL;
	const char *path = NULL, *service = NULL;
    network_connection_t *connection = NULL;

	/* This function gets the backing Connection object that describes the
	 * network configuration that the ActiveConnection object is actually using.
	 * The ActiveConnection object contains the mapping between the configuration
	 * and the actual network interfaces that are using that configuration.
	 */

	/* Create a D-Bus object proxy for the active connection object's properties */
	props_proxy = dbus_g_proxy_new_for_name (dbus,
	                                         NM_DBUS_SERVICE,
	                                         obj_path,
	                                         DBUS_INTERFACE_PROPERTIES);
	g_assert (props_proxy);
	
	/* Get the object path of the Connection details */
	if (!dbus_g_proxy_call (props_proxy, "Get", &error,
	                        G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
	                        G_TYPE_STRING, "Connection",
	                        G_TYPE_INVALID,
	                        G_TYPE_VALUE, &path_value,
	                        G_TYPE_INVALID)) {
		g_warning ("Failed to get active connection Connection property: %s",
		           error->message);
		g_error_free (error);
		goto out;
	}

	if (!G_VALUE_HOLDS (&path_value, DBUS_TYPE_G_OBJECT_PATH)) {
		g_warning ("Unexpected type returned getting Connection property: %s",
		           G_VALUE_TYPE_NAME (&path_value));
		goto out;
	}

	path = g_value_get_boxed (&path_value);
	if (!path) {
		g_warning ("Missing connection path!");
		goto out;
	}

#ifdef NM_DBUS_SERVICE_SYSTEM_SETTINGS
	/* Get the service name of the D-Bus service that provides the Connection */
	if (!dbus_g_proxy_call (props_proxy, "Get", &error,
	                        G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
	                        G_TYPE_STRING, "ServiceName",
	                        G_TYPE_INVALID,
	                        G_TYPE_VALUE, &serv_value,
	                        G_TYPE_INVALID)) {
		g_warning ("Failed to get active connection ServiceName property: %s",
		           error->message);
		g_error_free (error);
		goto out;
	}

	if (!G_VALUE_HOLDS (&serv_value, G_TYPE_STRING)) {
		g_warning ("Unexpected type returned getting Connection property: %s",
		           G_VALUE_TYPE_NAME (&serv_value));
		goto out;
	}

	service = g_value_get_string (&serv_value);
	if (!service) {
		g_warning ("Missing connection service name!");
		goto out;
	}
#else
	service = NM_DBUS_SERVICE;
#endif
	/* Print out the actual connection details */
	//print_connection (bus, service, path);
    connection = get_network_connection_by_path(dbus, service, path);

out:
	g_value_unset (&path_value);
#ifdef NM_DBUS_SERVICE_SYSTEM_SETTINGS
	g_value_unset (&serv_value);
#endif
	g_object_unref (props_proxy);
    DEBUG("get actived connection by path end");
    return connection;
}

network_connection_t *get_active_network_connections(DBusGConnection *dbus)
{
	DBusGProxy *props_proxy;
    GError *error = NULL;
	GValue value = { 0 };
	GPtrArray *paths = NULL;
	int i;
    network_connection_t *connection = NULL;


    props_proxy = dbus_g_proxy_new_for_name (dbus,
	                                         NM_DBUS_SERVICE,
	                                         NM_DBUS_PATH,
	                                         DBUS_INTERFACE_PROPERTIES);
    if (!dbus_g_proxy_call (props_proxy, "Get", &error,
	                        G_TYPE_STRING, NM_DBUS_INTERFACE,
	                        G_TYPE_STRING, "ActiveConnections",
	                        G_TYPE_INVALID,
	                        G_TYPE_VALUE, &value,
	                        G_TYPE_INVALID)) {
		g_warning ("Failed to get ActiveConnections property: %s", error->message);
		g_error_free (error);
		return NULL;
	}

	/* Make sure the ActiveConnections property is the type we expect it to be */
	if (!G_VALUE_HOLDS (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) {
		g_warning ("Unexpected type returned getting ActiveConnections: %s",
		           G_VALUE_TYPE_NAME (&value));
		goto out;
	}

	/* Extract the active connections array from the GValue */
	paths = g_value_get_boxed (&value);
	if (!paths) {
		g_warning ("Could not retrieve active connections property");
		goto out;
	}

	/* And print out the details of each active connection */
	for (i = 0; i < paths->len; i++)
    {
    
        char *connection_path = g_ptr_array_index (paths, i);
		DEBUG("actived connection path: %s", connection_path);
        network_connection_t *_connection = get_active_network_connection_by_path(dbus, connection_path);
        if (_connection)
        {
            _connection->next = connection;
            connection = _connection;
        }
    }

out:
	g_value_unset (&value);
    g_object_unref (props_proxy);

    return connection;
}

network_connection_t *get_network_connections(DBusGConnection *dbus, const char *setting_type)
{
	DBusGProxy *nm_proxy;
    
    GError *error = NULL;
	GPtrArray *con_array;
    network_connection_t *connection = NULL;

    int i;

    DEBUG("setting:%s", setting_type);

	nm_proxy = dbus_g_proxy_new_for_name (dbus,
	                                   setting_type,
	                                   NM_DBUS_PATH_SETTINGS,
	                                   NM_DBUS_IFACE_SETTINGS);

	g_assert (nm_proxy);


    /* Call ListConnections D-Bus method */
	dbus_g_proxy_call (nm_proxy, "ListConnections", &error,
	                   /* No input arguments */
	                   G_TYPE_INVALID,
	                   DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &con_array, /* Return values */
	                   G_TYPE_INVALID);

	for (i = 0; con_array && i < con_array->len; i++) {
		char *connection_path = g_ptr_array_index (con_array, i);
		DEBUG("%s\n", connection_path);
        network_connection_t *_connection = get_network_connection_by_path(dbus, setting_type, connection_path);
        if (_connection)
        {
            _connection->next = connection;
            connection = _connection;
        }
		g_free (connection_path);
	}

	g_ptr_array_free (con_array, TRUE);


	g_object_unref (nm_proxy);

	return connection;
}

GtkWidget *network_select_menu_new()
{
	GtkWidget *combobox;
	GtkListStore *model;
	GtkTreeIter iter;
	GtkCellRenderer *text_rend;

	combobox = gtk_combo_box_new();

	model = gtk_list_store_new(NETWORK_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);


    DBusGConnection *dbus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
#ifdef NM_DBUS_SERVICE_SYSTEM_SETTINGS
    network_connection_t *connection = get_network_connections(dbus, NM_DBUS_SERVICE_SYSTEM_SETTINGS);
    network_connection_t *connection2 = get_network_connections(dbus, NM_DBUS_SERVICE_USER_SETTINGS);
#else
    network_connection_t *connection = NULL;
    network_connection_t *connection2 = get_network_connections(dbus, NM_DBUS_SERVICE);
#endif
    dbus_g_connection_unref (dbus);

    network_connection_t *_tmp_con = connection; 

    if (_tmp_con != NULL)
    {
        while (_tmp_con->next != NULL)
            _tmp_con = _tmp_con->next;
        _tmp_con->next = connection2;
    }
    else
    {
        connection = connection2; 
    }
   
    _tmp_con = connection;  
    
    while (_tmp_con != NULL)
    {
        gtk_list_store_append (model, &iter);
        gtk_list_store_set (model, &iter,
                        NETWORK_CONNECT_ID, _tmp_con->id,
                        NETWORK_CONNECT_UUID, _tmp_con->uuid,
                        NETWORK_CONNECT_TYPE, _tmp_con->type,
                        -1);
        _tmp_con = _tmp_con->next;
    }

    network_connections_free(connection);

	gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(model));

	text_rend = gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), text_rend, TRUE);
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), text_rend, "markup", NETWORK_CONNECT_ID, NULL);
	g_object_set(text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);

    gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
	
	return combobox;
}


int active_status_by_network(AutoStatus *plg, network_connection_t *connection)
{
    ConfigRule *_tmp_rule = plg->rules;
	DEBUG("active_status_by_network start");
	DEBUG("connection uuid:%s", connection->uuid);
    while(_tmp_rule != NULL)
    {
	DEBUG("rule uuid:%s", _tmp_rule->uuid);
        if (_tmp_rule->rule_type == RULE_TYPE_NETWORK && strcmp(_tmp_rule->uuid, connection->uuid ) == 0 )
        {
            PurpleSavedStatus *status = get_saved_status(_tmp_rule->status_type, _tmp_rule->status_key);
            if (status != NULL)
            {
                purple_savedstatus_activate(status); 
                return 0;
            }
        }
        _tmp_rule = _tmp_rule->next; 
    }
	DEBUG("active_status_by_network end");
    return -1;
}

int is_network_connection_active(AutoStatus *plg, network_connection_t *connection)
{
    if (connection == NULL) return -1;
    if (plg->active_connections == NULL)  return -1;
    network_connection_t *_tmp_conn = plg->active_connections;
    while(_tmp_conn != NULL)
    {
        if (strcmp(_tmp_conn->uuid, connection->uuid) == 0) 
            return 0;
        _tmp_conn = _tmp_conn->next;
    }
    return -1;
}

